/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package mips;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.filechooser.FileNameExtensionFilter;

/**
 * Classe para a Criação da janela Gráfica onde será mostrado os resultados
 * obtidos pela simulação do processador MIPS.
 * 
 * @author Antonio J. L. Batista, Edurado E. Braga, Wagner S. Santos.
 */
public class Janela extends JFrame {
    
    // Atributos da classe
    private JLabel titulo;
    private JTextArea areaExecucao;
    private JTextArea areaRegistradores;
    private JTextArea areaMemoriaDados;
    private JTextArea areaMemoriaInstrucoes;
    private JButton executa;
    private JButton passoAPasso;
    private JButton escolheArquivo;
    private JFileChooser chooser;
    private String arquivoNome;
    private String arquivoSaida;
    private ArrayList<String> passos;
    private int contador;
    private boolean leuArquivo;
    
    /**
     * Cria uma janela gráfica para a apresentação dos resultado obtidos com 
     * a simulação do processador MIPS.
     */
    public Janela() {
        // Configura a janela
        setSize(1200, 1000);
        setVisible(true);
        setLayout(null);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   
        
        // Adiciona os campos onde serão mostrados os resultados
        setAreaExecucao();
        setAreaRegistradores();
        setAreaMemoriaDados();
        setTitulo();
        
        // Adiciona os botoes necessarios para permitir a simulação
        addBotaoPassoAPasso();
        addBotaoEscolheArquivo();
        
        // Inicialza os atributos usados durante a execução do programa.
        contador = 1;
        leuArquivo = false;
        arquivoNome = "";
        passos = new ArrayList<String>();
        chooser = new JFileChooser();
        repaint();
    }
    
    // Configura a área de execução
    private void setAreaExecucao() {
        
        areaExecucao = new JTextArea();
        areaExecucao.setLayout(null);
        areaExecucao.setBackground(Color.WHITE);
        areaExecucao.setEditable(false);
        add(areaExecucao);
        
        JScrollPane scroll =  new JScrollPane( areaExecucao );
        scroll.setBorder(new BevelBorder(1, Color.BLACK, Color.BLACK));
        scroll.setBounds(20, 50, 500, 650);
        JScrollBar bar = new JScrollBar();  
        scroll.add(bar);
        add(scroll);
        
    }
    
    // Configura a Área onde será mostrado os registradores
    private void setAreaRegistradores() {
        JLabel titulo = new JLabel("Registradores");
        titulo.setBounds(530, 30, 200, 20);
        add(titulo);
        
        areaRegistradores = new JTextArea();
        areaRegistradores.setLayout(null);
        areaRegistradores.setBackground(Color.WHITE);
        areaRegistradores.setEditable(false);
        areaRegistradores.setFont(new Font("Monospaced", Font.BOLD, 16));
        add(areaRegistradores);
        
        JScrollPane scroll =  new JScrollPane( areaRegistradores );
        scroll.setBorder(new BevelBorder(1, Color.RED, Color.RED));
        scroll.setBounds(530, 50, 200, 650);
        JScrollBar bar = new JScrollBar();  
        scroll.add(bar);
        add(scroll);
        
    }
    
    // Metodo para configurar a área onde será mostradoa os dados da memória de dados.
    private void setAreaMemoriaDados() {
        JLabel titulo = new JLabel("Memoria de Dados");
        titulo.setBounds(740, 30, 200, 20);
        add(titulo);
        
        areaMemoriaDados = new JTextArea();
        areaMemoriaDados.setBounds(740, 50, 450, 300);
        areaMemoriaDados.setLayout(null);
        areaMemoriaDados.setBackground(Color.WHITE);
        areaMemoriaDados.setEditable(false);
        areaMemoriaDados.setFont(new Font(Font.MONOSPACED, Font.LAYOUT_LEFT_TO_RIGHT, 14));
        add(areaMemoriaDados);
        
        JScrollPane scroll =  new JScrollPane( areaMemoriaDados );
        scroll.setBorder(new BevelBorder(1, Color.BLUE, Color.BLUE));
        scroll.setBounds(740, 50, 450, 300);
        JScrollBar bar = new JScrollBar();  
        scroll.add(bar);
        add(scroll);
        
    }
  
    // Metodo para configurar a área onde será mostrado os dados da memória de instruções.
    private void setAreaMemoriaInstrucoes() {
        JLabel titulo = new JLabel("Memoria de Instrucoes");
        titulo.setBounds(740, 380, 200, 20);
        add(titulo);
        
        areaMemoriaInstrucoes = new JTextArea();
        areaMemoriaInstrucoes.setLayout(null);
        areaMemoriaInstrucoes.setBackground(Color.WHITE);
        areaMemoriaInstrucoes.setEditable(false);
        areaMemoriaInstrucoes.setLineWrap(true);
        areaMemoriaInstrucoes.setVisible(true);
        areaMemoriaInstrucoes.setFont(new Font("Monospaced", Font.PLAIN, 16));

        JScrollPane scroll =  new JScrollPane( areaMemoriaInstrucoes );
        scroll.setBounds(740, 400, 450, 300);
        scroll.setBorder(new BevelBorder(1, Color.BLUE, Color.BLUE));
        JScrollBar bar = new JScrollBar();  
        scroll.add(bar);
        add(scroll);
        int k = 0;
        for(int i = 0; i < passos.size(); ++i) {
            if(passos.get(i).equals("#")) {
                k = i;
                break;
            }
            areaMemoriaInstrucoes.append(passos.get(i)+"\n");
        }
        removePassos(k);
        
    }
    
    // Meotod para configurar o titulo da area de execucoes.
    private void setTitulo() {
        titulo = new JLabel("MIPS: Resultados das Execucoes.");
        titulo.setLayout(null);
        titulo.setBounds(20, 20, 400, 40);
        add(titulo);
    }
    
    // Método para adicionar um botão para mostrar as execuções passo a passo.
    private void addBotaoPassoAPasso() {
        executa = new JButton("Play");
        executa.setBounds(260, 30, 100, 20);
        
        executa.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                int k = 0;
                if(passos.size() == 0) 
                    return;
                areaRegistradores.setText("");
                areaMemoriaDados.setText("");
                areaExecucao.append("----------------------------------------------");
                areaRegistradores.append(contador+" - Pipeline\n");
                areaMemoriaDados.append(contador+" - Pipeline\n\n");
                for(int i = 0; i < passos.size(); ++i) {
                    
                    if(passos.get(i).equals("#")) {
                        k = i;
                        break;
                    }
                    areaRegistradores.append(passos.get(i)+"\n");
                    
                }
                
                removePassos(k);
                
                for(int i = 0; i < passos.size(); ++i) {
                    
                    if(passos.get(i).equals("#")) {
                        k = i;
                        break;
                    }
                    areaMemoriaDados.append(passos.get(i)+"\n\n");
                    
                }
                
                removePassos(k);
                
                for(int i = 0; i < passos.size(); ++i) {
                    
                    if(passos.get(i).equals("#")) {
                        k = i;
                        break;
                    }
                    areaExecucao.append(passos.get(i)+"\n\n");
                    
                }
                
                removePassos(k);
                contador++;
            }
            
            
        });
        
        add(executa);
        
    }
    
    // Método para configurar uma janela para a escolha do arquivo de instruções.
    private void addChooser() {
        chooser.setDialogTitle("Arquivo Programa:");
        FileNameExtensionFilter filter = new FileNameExtensionFilter("Text Files", "txt");
        chooser.setFileFilter(filter);
        if(JFileChooser.CANCEL_OPTION == chooser.showOpenDialog(null)) {
            JOptionPane.showMessageDialog(null, "Arquivo Nao Selecionado", "Aviso", JOptionPane.INFORMATION_MESSAGE);
        }
        leuArquivo = true;
        setArquivoNome(chooser.getSelectedFile().getPath());
    }
    
    
    // Adiciona um botao para que um arquivo possa ser selecionado.
    private void addBotaoEscolheArquivo() {
        executa = new JButton("Arquivo");
        executa.setBounds(20, 10, 100, 20);
        
        executa.addActionListener(new ActionListener() {

            public void actionPerformed(ActionEvent ae) {
                addChooser();
            }
        });
        
        add(executa);
    }
    
    
    private void setArquivoNome(String nome) {
        arquivoNome = nome;
    }
    
    /**
     * Método para inicalizar os Passos que serão mostrados na simulação.
     * @throws FileNotFoundException Exceção gerada quando um arquivo não foi lido.
     */
    public void inicializaPassos() throws FileNotFoundException {
        arquivoSaida = chooser.getSelectedFile().getPath().replaceAll(".txt", "_Saida.txt");
        Scanner arquivo = new Scanner(new File(arquivoSaida));
        while(arquivo.hasNextLine()) {
            
            String linha = arquivo.nextLine();
                
            // Leitura das instrucoes que serao executadas
            if(linha.equals("Instrucoes a serem executadas:")) {
                linha = arquivo.nextLine();
                while(!linha.endsWith("PIPELINE")){
                    passos.add(linha);
                    linha = arquivo.nextLine();
                }
                passos.add("#");
            }
            
            // Adicionando os passos do pipeline
            if(linha.endsWith("PIPELINE")) {
                String[] numbers = linha.split(" ");
                passos.add(numbers[0]);
                linha = arquivo.nextLine();
                linha = arquivo.nextLine();
            }
            
            // Leitura de todos os registradores.
            if(linha.equals("Registradores")) {
                linha = arquivo.nextLine();
                while(!linha.endsWith("Memoria de Dados")){
                    passos.add(linha);
                    linha = arquivo.nextLine();
                }
                passos.add("#");
                linha = arquivo.nextLine();
            }
            
            // Leitura dos dados na memoria de dados.
            if(linha.equals("Memoria de Dados")) {
                linha = arquivo.nextLine();
                while(!linha.startsWith("Busca") && !linha.endsWith("Finalizado") && !linha.isEmpty()){
                    passos.add(linha);
                    linha = arquivo.nextLine();
                }
                passos.add("#");
            }
            
            if(linha.isEmpty()){
                while(!linha.endsWith("Finalizado")){
                    passos.add(linha);
                    linha = arquivo.nextLine();
                }
                passos.add("#");
                linha = arquivo.nextLine();
                
            }    
            
        } // Fim do while. 
        
        setAreaMemoriaInstrucoes();
        repaint();
    }
    
    // Remove os passo qye já foram mostrados.
    private void removePassos(int limite) {
        for(int i = 0; i <= limite; ++i) {
            if(passos.isEmpty())
                return;
            passos.remove(0);
        }
        
    }

    /**
     * Método que verifica se um arquivo foi lido.
     * @return 
     */
    public boolean getLeuArquivo() {
        return leuArquivo;
    }

    /**
     * Método para retornar o nome do arquivo.
     * @return 
     */
    public String getArquivoNome() {
        return arquivoNome;
    }
    
} // Fim da classe.
